package contract_client

import (
	"crypto/x509"
	"fmt"
	beego "github.com/beego/beego/v2/server/web"
	"github.com/hyperledger/fabric-gateway/pkg/client"
	"github.com/hyperledger/fabric-gateway/pkg/identity"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"
	"os"
	"path"
	"time"
)

//TODO:处理error

// InitLedger initializes the ledger by submitting a transaction.
func InitContractClient() *client.Contract {
	// The gRPC client connection should be shared by all Gateway connections to this endpoint
	clientConnection := newGrpcConnection()

	id := newIdentity()
	sign := newSign()

	// Create a Gateway connection for a specific client identity
	gw, err := client.Connect(
		id,
		client.WithSign(sign),
		client.WithClientConnection(clientConnection),
		// Default timeouts for different gRPC calls
		client.WithEvaluateTimeout(5*time.Second),
		client.WithEndorseTimeout(15*time.Second),
		client.WithSubmitTimeout(5*time.Second),
		client.WithCommitStatusTimeout(1*time.Minute),
	)
	if err != nil {
		//log.Error(err.Error())

	}

	// Override default values for chaincode and channel name as they may differ in testing contexts.
	network := gw.GetNetwork(beego.AppConfig.DefaultString("contracts::channelName", ""))

	contract := network.GetContract(beego.AppConfig.DefaultString("contracts::chaincodeName", ""))

	return contract
}

// newGrpcConnection creates a gRPC connection to the Gateway service.
func newGrpcConnection() *grpc.ClientConn {
	certificate, err := loadCertificate(beego.AppConfig.DefaultString("contracts::tlsCertPath", ""))
	if err != nil {
		//log.Error(err.Error())
	}

	certPool := x509.NewCertPool()

	certPool.AddCert(certificate)

	transportCredentials := credentials.NewClientTLSFromCert(certPool, beego.AppConfig.DefaultString("contracts::gatewayPeer", ""))

	connection, err := grpc.Dial(beego.AppConfig.DefaultString("contracts::peerEndpoint", ""), grpc.WithTransportCredentials(transportCredentials))
	if err != nil {
		//log.Errorf("failed to create gRPC connection: %w", err.Error())

	}

	return connection
}

// newIdentity creates a client identity for this Gateway connection using an X.509 certificate.
func newIdentity() *identity.X509Identity {
	certificate, err := loadCertificate(beego.AppConfig.DefaultString("contracts::certPath", ""))
	if err != nil {
		//log.Error(err.Error())
	}

	id, err := identity.NewX509Identity(beego.AppConfig.DefaultString("contracts::mspID", ""), certificate)
	if err != nil {
		//log.Error(err.Error())
	}

	return id
}

// loadCertificate  creates a client certificate from a PEM file.
func loadCertificate(filename string) (*x509.Certificate, error) {

	certificatePEM, err := os.ReadFile(filename)
	if err != nil {
		return nil, fmt.Errorf("failed to read certificate file: %w", err)
	}

	return identity.CertificateFromPEM(certificatePEM)
}

// newSign creates a function that generates a digital signature from a message digest using a private key.
func newSign() identity.Sign {

	files, err := os.ReadDir(beego.AppConfig.DefaultString("contracts::keyPath", ""))
	if err != nil {
		//log.Errorf("failed to read private key directory: %w", err.Error())
	}

	privateKeyPEM, err := os.ReadFile(path.Join(beego.AppConfig.DefaultString("contracts::keyPath", ""), files[0].Name()))
	if err != nil {
		//log.Errorf("failed to read private key file: %w", err.Error())

	}

	privateKey, err := identity.PrivateKeyFromPEM(privateKeyPEM)
	if err != nil {
		//log.Error(err.Error())
	}

	sign, err := identity.NewPrivateKeySign(privateKey)
	if err != nil {
		//log.Error(err.Error())
	}

	return sign
}
